package fr.utt.lo02.CrazyEights.model.piles;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Observable;

import fr.utt.lo02.CrazyEights.model.Game;
import fr.utt.lo02.CrazyEights.model.cards.Card;
import fr.utt.lo02.CrazyEights.model.cards.CardRank;
import fr.utt.lo02.CrazyEights.model.cards.CardSuit;
import fr.utt.lo02.CrazyEights.model.exceptions.EmptyPileException;


/**
 * Represents a discardPile
 * @author Jeremy
 *
 */
public class DiscardPile extends Observable implements Serializable{

	private static final long serialVersionUID = 1L;
	
	/**
	 * Cards in pile
	 */
	private ArrayList<Card> cardsInPile = new ArrayList<Card>();
	/**
	 * Actual suit to play
	 */
	private CardSuit gameSuit;
	/**
	 * Consecutive aces
	 */
	private int consecutiveAces = 0;
	
	/**
	 * Create the pile putting the first card
	 * @param stockPile pile where we take the first card
	 */
	public DiscardPile(StockPile stockPile) {
		try {
			cardsInPile.add(stockPile.draw());
			while(this.isSpecial()){
				cardsInPile.add(stockPile.draw());
			}
			this.setGameSuit();
			setChanged();
			notifyObservers();
		} catch (EmptyPileException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Check if the card on top is special
	 * @return true if the card is special, false otherwise
	 */
	public boolean isSpecial(){
		boolean isSpecial;
		switch(getCardOnTop().getRank()){
		case Ace:
			isSpecial = true;
			break;
		case Two:
			isSpecial = true;
			break;
		case Seven:
			isSpecial = true;
			break;
		case Eight:
			isSpecial = true;
			break;
		case Ten:
			isSpecial = true;
			break;
		case Joker:
			isSpecial = true;
			break;
		default:
			isSpecial = false;
				break;
		}
		return isSpecial;
	}
	
	/**
	 * check if the card is playable
	 * @param card the card to check
	 * @return true if the card is playable, false otherwise
	 */
	public boolean isPlayable(Card card){
		Card cardOnTop = getCardOnTop();
		boolean playable = false;
		
		if(card.getRank()!=CardRank.Ace && this.consecutiveAces>0){
			playable = false;
		}else if(card.getRank()==CardRank.Eight && cardOnTop.getRank()!=CardRank.Ace && Game.getInstance().getPlayersList().getCurrentPlayer().getNbCardsInHand()>1){
			playable = true;
		}else if(card.getRank()==CardRank.Joker && cardOnTop.getRank()!=CardRank.Ace && Game.getInstance().getPlayersList().getCurrentPlayer().getNbCardsInHand()>1){
			playable = true;
		}else if(card.getRank()==CardRank.Ten && (this.getGameSuit()==card.getSuit() || cardOnTop.getRank()==CardRank.Ten)){
			playable = true;
		}else if(card.getRank()==CardRank.Seven && (this.getGameSuit()==card.getSuit() || cardOnTop.getRank()==CardRank.Seven)){
			playable = true;
		}else if(card.getRank()==CardRank.Two && (this.getGameSuit()==card.getSuit() || cardOnTop.getRank()==CardRank.Two)){
			playable = true;
		}else if(card.getSuit()==this.getGameSuit()){
			playable = true;
		}else if(card.getRank()==cardOnTop.getRank()){
			playable = true;
		}
		
		return playable;
	}
	
	/**
	 * Add card on the pile
	 * @param card the card to add
	 */
	public void addCard(Card card){
		if(isPlayable(card)){
			cardsInPile.add(card);
			this.setGameSuit();
			setChanged();
			notifyObservers();
		}
		if(Game.getInstance().getStockPile().isEmpty())
			Game.getInstance().getStockPile().refillPile();
	}
	
	public Card getCardOnTop(){
		return cardsInPile.get(cardsInPile.size()-1);
	}
	
	public String toString(){
		return cardsInPile.get(cardsInPile.size()-1).toString();
	}
	
	public CardSuit getGameSuit(){
		return this.gameSuit;
	}
	
	public void setGameSuit(){
		this.gameSuit = this.getCardOnTop().getSuit();
		setChanged();
		notifyObservers();
	}
	
	public void setGameSuit(CardSuit suit){
		this.gameSuit = suit;
		setChanged();
		notifyObservers();
	}
	
	/**
	 * add an ace to consecutiveAces
	 */
	public void addAce(){
		this.consecutiveAces++;
	}
	
	public int getConsecutiveAces(){
		return this.consecutiveAces;
	}
	
	/**
	 * reset the number of consecutive aces
	 */
	public void resetConsecutiveAces(){
		this.consecutiveAces = 0;
	}
	
	/**
	 * Get all cards in pile except the card on top and remove them from the pile
	 * @return all cards in pile except the card on top
	 */
	public ArrayList<Card> getExtraCardsAndEmpty(){
		ArrayList<Card> extraCards = new ArrayList<Card>();
		if(cardsInPile.size()>1){
			extraCards.addAll(cardsInPile);
			extraCards.remove(extraCards.size()-1);
			cardsInPile.removeAll(extraCards);
			Collections.shuffle(extraCards);
		}
		return extraCards;
	}
}
